package cn.mazexal.examapi.common.filter;


import cn.mazexal.examapi.common.anno.PermitGuest;
import cn.mazexal.examapi.common.models.*;
import cn.mazexal.examapi.models.bo.Credentials;
import cn.mazexal.examapi.models.enums.RequestHeaderEnum;
import cn.mazexal.examapi.models.redisKeys.RedisCommonKey;
import cn.mazexal.examapi.models.redisKeys.RedisUserKey;
import cn.mazexal.examapi.services.RedisService;
import cn.mazexal.examapi.utils.JWTProvider;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.concurrent.TimeUnit;

/**
 * 访问凭证过滤器
 *
 * @author Lay
 * @date 2024/7/30
 */
@Component
@Slf4j
public class CredentialsInterceptor implements HandlerInterceptor {

    @Resource
    private JWTProvider jwtProvider;

    @Resource
    private RedisService redisService;

    @Override
    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response,
                             Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            String reqPath = request.getServletPath();
            if(reqPath.contains("well-known")){
                // 这是域名申请用的
                return true;
            }
            if(reqPath.contains("view")){
                // 这是特定几个
                return true;
            }

            String requestId = requestId(request);
            String key = RedisCommonKey.getQuestKey(requestId);
            if (!redisService.tryLock(key, RedisCommonKey.keyValue, 2, TimeUnit.SECONDS)) {
                throw new BizException(new CustomerError("500", "请求过于频繁"));
            }

            // 判断是否有访客注解
            if (((HandlerMethod) handler).getMethod().isAnnotationPresent(PermitGuest.class)) {
                // 访客接口，直接放行
                return true;
            }

            // 获取请求头中的访问凭证
            String token = getHeaderToken(request);
            if (StringUtils.isBlank(token)) {
                // 访问凭证无效
                throw new UnauthorizedException();
            }

            // 验证访问凭证
            Credentials credentials = jwtProvider.decode(token);
            if (credentials == null) {
                // 访问凭证无效
                throw new UnauthorizedException();
            }
            Long userId = credentials.getUserId();
            String platform = request.getHeader(RequestHeaderEnum.PLATFORM.getValue());
            String userToken = String.valueOf(redisService.hashGet(RedisUserKey.getUserKey(userId), platform));
            String shortToken = jwtProvider.getShortToken(token);
            if (!shortToken.equals(userToken)) {
                throw new UnauthorizedException();
            }
            return true;
        } else {
            // 服务端不提供静态资源访问，如果不是走的方法直接 404
            return false;
        }

    }

    private String requestId(HttpServletRequest request) {
        return request.getHeader(RequestHeaderEnum.REQUEST_ID.getValue());
    }


    private String getHeaderToken(HttpServletRequest request) {
        return request.getHeader(RequestHeaderEnum.USER_TOKEN.getValue());
    }
}
